#include "SDL2/SDL.h"
#include <Eigen/Dense>
#include <stdio.h>
#include <iostream>
using namespace Eigen;
using namespace std;
#define MYSCREEN_WIDTH 640
#define MYSCREEN_HEIGHT 480

typedef Array4f MyVector;

typedef vector<MyVector> Triangle;
// xmin,ymin,xmax,ymax
void GetRect(Triangle triangle, MyVector *res)
{
    float xmin = 65535;
    float ymin = 65535;
    float xmax = -1;
    float ymax = -1;
    for (int i = 0; i < triangle.size(); i++)
    {
        if (triangle[i](0) > xmax)
        {
            xmax = triangle[i](0);
        }
        if (triangle[i](1) > ymax)
        {
            ymax = triangle[i](1);
        }
        if (triangle[i](0) < xmin)
        {
            xmin = triangle[i](0);
        }
        if (triangle[i](1) < ymin)
        {
            ymin = triangle[i](1);
        }
    }
    (*res) << xmin, ymin, xmax, ymax;
}
bool CheckInBox(MyVector matrixPoint, MyVector rect)
{
    if (matrixPoint(0) > rect(0) && matrixPoint(1) > rect(1) && matrixPoint(0) < rect(2) && matrixPoint(1) < rect(3))
    {
        return true;
    }
    return false;
}
bool IsInTriangle(int i, int j, Triangle &triangle)
{
    double checkBuffer[3];
    for (int t = 0; t < 3; t++)
    {

        MyVector tp;
        tp << j + 0.5, i + 0.5, 0, 0;
        MyVector vp = tp - triangle[t];
        // cout << vp << endl;
        MyVector vl = triangle[(t + 1) % 3] - triangle[t];
        // cout << vl << endl;
        Vector3d vp_2d, vl_2d;
        vp_2d << vp(0), vp(1), 0;
        vl_2d << vl(0), vl(1), 0;
        auto v = vl_2d.cross(vp_2d);
        checkBuffer[t] = v(2);
        // cout << v << endl;
    }
    if (checkBuffer[0] > 0 && checkBuffer[1] > 0 && checkBuffer[2] > 0)
    {
        return true;
    }
    if (checkBuffer[0] < 0 && checkBuffer[1] < 0 && checkBuffer[2] < 0)
    {
        return true;
    }
    return false;
}
void ShowTriangle(MatrixXd &matrix, Triangle triangle)
{
    MyVector rect;
    GetRect(triangle, &rect);
    for (int i = rect(1); i < rect(3); i++)
    {
        for (int j = rect(0); j < rect(2); j++)
        {
            matrix(i, j) = IsInTriangle(i, j, triangle) ? 255 : 0;
        }
    }
}

typedef struct MyScreen
{
    int height;
    int width;
    SDL_Window *window;
    SDL_Renderer *renderer;
} MyScreen;
void MyScreen_Init(MyScreen *myscreen, int width = MYSCREEN_WIDTH, int height = MYSCREEN_HEIGHT)
{
    myscreen->height = height;
    myscreen->width = width;

    myscreen->window = SDL_CreateWindow("MYSCREEN!", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 0);
    myscreen->renderer = SDL_CreateRenderer(myscreen->window, -1, 0);
}

void MyScreen_Refresh(MyScreen *myscreen, MatrixXd &matrix)
{

    SDL_Rect viewport;

    // 获取渲染目标（render target）的视口（viewport）信息
    SDL_RenderGetViewport(myscreen->renderer, &viewport);
    int w = myscreen->width;
    int h = myscreen->height;

    for (int i = 0; i < h; i++)
    {
        for (int j = 0; j < w; j++)
        {

            Uint8 p = (matrix(i, j));
            // Uint8 p=255;
            SDL_SetRenderDrawColor(myscreen->renderer, p, p, p, 255);
            SDL_RenderDrawPoint(myscreen->renderer, j, i);
        }
    }
    SDL_RenderPresent(myscreen->renderer);
}
bool MyScreen_Waykey()
{
    SDL_Event event;
    if (SDL_WaitEvent(&event))
    {
        if (event.type == SDL_QUIT || event.type == SDL_KEYUP)
        {
            return true;
        }
    }
    return false;
}
void MyScreen_Quit()
{
    SDL_Quit();
}
int main(int argc, char *argv[])
{
    MyScreen myscreen;
    MyVector p1, p2, p3, rect;
    Triangle t;
    p1 << 200, 200, 0, 0;
    p2 << 500, 200, 0, 0;
    p3 << 300, 400, 0, 0;

    t.push_back(p1);
    t.push_back(p2);
    t.push_back(p3);
    MyScreen_Init(&myscreen, MYSCREEN_WIDTH, MYSCREEN_HEIGHT);
    int i = 0;
    while (true)
    {
        i++;
        // MatrixXd matrix = MatrixXd::Random(MYSCREEN_HEIGHT, MYSCREEN_WIDTH).cwiseAbs() * 255;
        MatrixXd matrix = MatrixXd::Zero(MYSCREEN_HEIGHT, MYSCREEN_WIDTH);
        ShowTriangle(matrix, t);
        // cout<<matrix<<endl;

        MyScreen_Refresh(&myscreen, matrix);
        if (MyScreen_Waykey() || i > 20)
        {
            break;
        }
    }
    MyScreen_Quit();
}